# 在本实例中实现mnist数据集的神经网络
import os
import pickle
import sys

import numpy  as np

sys.path.append(os.pardir)  # 在程序路径中添加当前目录的父目录，用来添加mnist数据集
from dataset.mnist import load_mnist
from common.functions import sigmoid as sigmod


# get dataset
def get_dataset():
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
    return x_test, t_test


# init_network
def init_network():
    with open('sample_weight.pkl', mode='rb') as f:  # 这里表示以二进制的方式读取文件，同时将打开的文件起一个别名
        network = pickle.load(f)  # 将文件用pickle中装载读取
    return network


# predict
def softmax1(x):
    max = np.max(x)
    exp_x = np.exp(x - max)
    sum_exp_x = np.sum(exp_x)
    y = exp_x / sum_exp_x

    return y


def softmax(x):
    if x.ndim == 2:  # 判断如果是元祖是二维的
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T

    x = x - np.max(x)  # 溢出对策
    return np.exp(x) / np.sum(np.exp(x))


def predict(network, x):
    W1 = network['W1']
    W2 = network['W2']
    W3 = network['W3']

    b1 = network['b1']
    b2 = network['b2']
    b3 = network['b3']

    a1 = np.dot(x, W1) + b1
    z1 = sigmod(a1)  # 在本例中激活函数的选择：因为是要进行分类，所以激活函数选择softmax函数

    a2 = np.dot(z1, W2) + b2
    z2 = sigmod(a2)  # 在本例中激活函数的选择：因为是要进行分类，所以激活函数选择softmax函数

    a3 = np.dot(z2, W3) + b3
    y = softmax(a3)  # 在本例中激活函数的选择：因为是要进行分类，所以激活函数选择softmax函数

    return y


# 主入口，概率预测
x, t = get_dataset()
accuracy_cnt = 0  # 准确度
network = init_network()

for i in range(len(x)):
    y = predict(network, x[i])  # 神经网络预测结果
    p = np.argmax(y)  # 取神经网络预测结果中概率最高的索引
    # 如果预测正确，准确度+1
    if p == t[i]:
        accuracy_cnt += 1

print('Accuracy is: ' + str(accuracy_cnt / len(x) * 100) + ' %')
